/*
 * MusicPlayer.cpp
 *
 *  Created on: 2010-09-22
 *      Author: Administrateur
 */
#include "Epik_MusicPlayer.h"
#include <pspkernel.h>
#include <stdio.h>
#include <pspaudio.h>
#include <pspmp3.h>
#include <psputility.h>
#include <pspdisplay.h>

int fillStreamBuffer(int fd, int handle);
int PlayerThread(SceSize args, void *argp);

Epik_MusicPlayer::Epik_MusicPlayer(bool *running)
{
	running_ = running;
	int status;

	status = sceUtilityLoadModule(PSP_MODULE_AV_AVCODEC);
	if( status<0 )
	{/*error*/}

	status = sceUtilityLoadModule(PSP_MODULE_AV_MP3);
	if( status<0 )
	{/*error*/}

	file_ = sceIoOpen( "Music/Lance Battle (Ultimate Version).mp3", PSP_O_RDONLY, 0777 );
	if( file_<0 )
	{/*error*/}

	status = sceMp3InitResource();
	if( status<0 )
	{/*error*/}

	mp3Init_.mp3StreamStart = 0;
	mp3Init_.mp3StreamEnd = sceIoLseek32( file_, 0, SEEK_END );
	mp3Init_.unk1 = 0;
	mp3Init_.unk2 = 0;
	mp3Init_.mp3Buf = mp3Buf_;
	mp3Init_.mp3BufSize = sizeof(mp3Buf_);
	mp3Init_.pcmBuf = pcmBuf_;
	mp3Init_.pcmBufSize = sizeof(pcmBuf_);

	handle_ = sceMp3ReserveMp3Handle(&mp3Init_);
	if( handle_<0 )
	{/*error*/}

	fillStreamBuffer(file_, handle_);

	status = sceMp3Init(handle_);
	if( status<0 )
	{/*error*/}

	channel_ = -1;
	samplingRate_ = sceMp3GetSamplingRate(handle_);
	numChannels_ = sceMp3GetMp3ChannelNum(handle_);
	lastDecoded_ = 0;
	volume_ = 0x6000;//PSP_AUDIO_VOLUME_MAX*0.75;
	numPlayed_ = 0;
	playing_ = false;
	paused_ = false;
	loop_ = true;
}


Epik_MusicPlayer::~Epik_MusicPlayer()
{
	// TODO Auto-generated destructor stub
}


void Epik_MusicPlayer::Run()
{
	while(*running_&&playing_)
	{
		// normally get sampling and output here... so what
		if(!paused_)
		{
/*
			sceDisplayWaitVblankStart();
			pspDebugScreenSetXY(0, 0);
			printf("HelloWorld 0.1 with audio?\n\n");
			printf("Playing '%s'...\n", "Music/Lance Battle (Ultimate Version).mp3");
			printf(" %i Hz\n", samplingRate_);
			printf(" %i kbit/s\n", sceMp3GetBitRate( handle_ ));
			printf(" %s\n", numChannels_==2?"Stereo":"Mono");
			printf(" %s\n\n", (!loop_)?"No loop":"Loop");
			int playTime = samplingRate_>0?numPlayed_ / samplingRate_:0;
			printf(" Playtime: %02i:%02i\n", playTime/60, playTime%60 );
//				printf("\n\n\nPress CIRCLE to Pause/Resume playback\nPress TRIANGLE to reset playback\nPress CROSS to switch loop mode\nPress SQUARE to stop playback and quit\n");
*/

			// Check to see if the buffer needs to feed
			if(sceMp3CheckStreamDataNeeded(handle_)>0)
				fillStreamBuffer(file_, handle_);

			// Decode some samples
			short *buf;
			u32 bytesDecoded;
			int retries = 0;
			// A Retry is needed in case we reached the end and
			// need to loop around
			for( ; retries<1; retries++)	// only 1 retry
			{
				bytesDecoded = sceMp3Decode(handle_, &buf);
				if(bytesDecoded>0)
					break;
				if(sceMp3CheckStreamDataNeeded(handle_)<=0)
					break;
				if(!fillStreamBuffer(file_, handle_))
					numPlayed_ = 0;
			}

			if(bytesDecoded<0 && bytesDecoded!=0x80671402)
			{/*error=bytesDecoded*/}

			// No more decoding = EOF
			if(bytesDecoded==0 || bytesDecoded==0x80671402)
			{
				if (loop_)
					paused_ = false;
				else
					paused_ = true;
				sceMp3ResetPlayPosition(handle_);
				numPlayed_ = 0;
			}
			else
			{
				// Reserve the audio channel for output (in case
				// another process is using audio)
				if(channel_>=0)
					sceAudioSRCChRelease();

				channel_ = sceAudioSRCChReserve(bytesDecoded/(2*numChannels_), samplingRate_, numChannels_);
			}
			numPlayed_ += sceAudioSRCOutputBlocking(volume_, buf);
		}
	}

	// Cleanup
	if(channel_>=0)
		sceAudioSRCChRelease();

	int status = sceMp3ReleaseMp3Handle(handle_);
	if(status<0)
	{/*error*/}

	// Close file...
	status = sceIoClose(file_);
	if(status<0)
	{/*error*/}
}



void Epik_MusicPlayer::Play()
{
	if (!playing_)
	{
		playing_ = true;
		thid_ = sceKernelCreateThread("musicPlayer", PlayerThread, 0x16, 256*1024, 0, NULL);

		pspDebugScreenPrintf("thid_\t=\t%X\n", thid_);
		if(thid_)
			sceKernelStartThread(thid_, sizeof(*this), (void *)this);
	}
	paused_ = false;
}



void Epik_MusicPlayer::Pause()
{
	paused_ = !paused_;
}



void Epik_MusicPlayer::Stop()
{
	paused_ = true;
	playing_ = false;
	sceKernelWaitThreadEnd(thid_, NULL);
	sceKernelTerminateThread(thid_);
}

int fillStreamBuffer(int fd, int handle)
{
	SceUChar8* dst;
	int write;
	int pos;

	int status = sceMp3GetInfoToAddStreamData( handle, &dst, &write, &pos);
	if(status<0)
	{/*error*/}

	// Seek file to position requested
	status = sceIoLseek32(fd, pos, SEEK_SET);
	if(status<0)
	{/*error*/}

	int read = sceIoRead(fd, dst, write);
	if(read<0)
	{/*error*/}

	if(read==0)
	{   //EOF?
		return 0;
	}

	// We need to tell the PSP how much we wrote on the stream
	status = sceMp3NotifyAddStreamData(handle, read);
	if(status<0)
	{/*error*/}

	return (pos>0);
}

int PlayerThread(SceSize args, void *argp)
{
	Epik_MusicPlayer *mp = reinterpret_cast<Epik_MusicPlayer*>(argp);

	mp->Run();
	mp->Stop();

	return 0;
}

